--[[
********************************************************************************
                    created :           2020/06/14
                    author   :           唐韡
                    purpose :           Lua 开发日常使用的小工具（ToAdd...）
********************************************************************************
--]]
---常用工具
LuaKits = {}
--*************************  Class (start)  *************************
---1.继承
ClassContainner = {} --父类、子类容器
function Class(super)
    local class_key = {}  --子类在容器中的key值
    class_key.New = function(o)
        local m = o or {}  --子类
        setmetatable(m,{__index = ClassContainner[class_key]})
        return m
    end

    local class_value = {}  --子类在容器中的value值（存储 class 中的成员变量、成员方法）
    ClassContainner[class_key] = class_value
    setmetatable(class_key,{
        __newindex = function(t,k,v)
            class_value[k] = v  --add成员变量、成员方法
        end
    })

    if super then  --存在父类
        setmetatable(class_value,{
            __index = function(t,k)
                local super_value = ClassContainner[super][k]  --返回父类的成员变量、成员方法
                class_value[k] = super_value
                return super_value
            end
        })
    end

    return class_key
end

---2.单例模板
Singleton = {}
Singleton.__index = Singleton
function Singleton.New(o)
    m = o or {}
    setmetatable(m,Singleton)
    return m
end
--获取单例实例
function Singleton.GetInstance()
    if not Singleton.instance then
        Singleton.instance = Singleton.New()
    end
    return Singleton.instance
end
--*************************  Class (end)  *************************
--*************************  Custom Containner (start)  *************************
---列表
---{ New , GetLen , IsEmpty , Add , Insert , Get , RemoveAt , Remove , IndexOf , LastIndexOf , Contains , Find , GetIterator , Clear }
function LuaKits.NewList()
    local List = {}
    List.__index = List
    ---构造
    function List:New()
        local m = {count = 0}
        setmetatable(m,List)
        return m
    end
    ---获取队列内元素个数
    function List:GetLen()
        return self.count
    end
    ---是否为空
    function List:IsEmpty()
        return self.count == 0
    end
    ---添加元素
    function List:Add(value)
        self.count = self.count + 1
        self[self.count] = value
    end
    ---将元素插入指定索引
    function List:Insert(value,index)
        if index > self.count + 1 then error('List insert error , index out of range.') return end
        for i = self.count , index , -1 do
            self[i + 1] = self[i]
        end
        self[index] = value
        self.count = self.count + 1
    end
    ---获取指定索引元素
    function List:Get(index)
        if index > self.count then error('List get value error , index out of range.') return end
        return self[index]
    end
    ---移除指定索引的元素（移除后元素索引会重排）
    function List:RemoveAt(index)
        if index > self.count then
            error('List RemoveAt Func Error , index(%d) out of range(%d)',index,self.count)
            return
        end
        --print(index + 1,self.count)
        for i = index + 1 , self.count do
            --print(self[i-1],self[i])
            self[i-1] = self[i]
            --print(self[i-1],self[i])
        end
        self.count = self.count - 1
    end
    ---移除指定元素
    function List:Remove(item)
        local index = self:LastIndexOf(item)
        if index > 0 then
            self:RemoveAt(index)
            self:Remove(item)
        end
    end
    ---获取指定元素的索引（正向搜索）
    function List:IndexOf(value)
        for i = 1 , self.count do
            if self[i] == value then
                return i
            end
        end
        return 0
    end
    ---获取指定元素的索引（逆向搜索）
    function List:LastIndexOf(value)
        for i = self.count , 1 , -1 do
            if self[i] == value then
                return i
            end
        end
        return 0
    end
    ---返回是否包含指定元素
    function List:Contains(value)
        for i = 1 , self.count do
            if self[i] == value then
                return true
            end
        end
        return false
    end
    ---搜索满足条件的元素（predicate 为条件 Func）
    function List:Find(predicate)
        if not predicate or type(predicate)~= 'function' then
            error('Error: Find predicate invalid.')
        end
        for i = 1 , self.count do
            if predicate(self[i]) then
                return self[i]
            end
        end
        return nil
    end
    ---获取迭代器
    function List:GetIterator()
        local i = 0
        return function()
            i = i + 1
            if i <= self.count then
                return self[i]
            else
                return nil
            end
        end
    end
    ---清空 List
    function List:Clear()
        for i = self.count , 1 , -1 do
            self[i] = nil
        end
        self.count = 0
    end
    return List
end

---栈（先进后出）
---{ New , GetLen , IsEmpty , Push , Pop , Peek , GetIterator , Clear }
function LuaKits.NewStack()
    local Stack = {}
    Stack.__index = Stack
    ---构造
    function Stack:New()
        local m = {count = 0}
        setmetatable(m,Stack)
        return m
    end
    ---获取栈内元素个数
    function Stack:GetLen()
        return self.count
    end
    ---是否为空
    function Stack:IsEmpty()
        return self.count == 0
    end
    ---入栈
    function Stack:Push(value)
        self.count = self.count + 1
        self[self.count] = value
    end
    ---出栈
    function Stack:Pop()
        if self.count == 0 then print('Stack is empty.') return nil end
        local value = self[self.count]
        self[self.count] = nil
        self.count = self.count - 1
        return value
    end
    ---读取栈顶元素
    function Stack:Peek()
        if self.count == 0 then print('Stack is empty.')return nil end
        return self[self.count]
    end
    ---获取遍栈历内部元素的迭代器
    function Stack:GetIterator()
        local index = self.count + 1
        return function()
            index = index - 1
            return self[index]
        end
    end
    ---清空栈
    function Stack:Clear()
        if self.count == 0 then return end
        for i = 1 , self.count do
            self[i] = nil
        end
        self.count = 0
    end
    return Stack
end

---队列（先进先出）
---{ New , GetLen , IsEmpty , Push , Pop , Peek , GetIterator , Clear }
function LuaKits.NewQueue()
    local Queue = {}
    Queue.__index = Queue
    ---构造
    function Queue:New()
        local m = {first = 1,last = 0,count = 0}
        setmetatable(m,Queue)
        return m
    end
    ---获取队列内元素个数
    function Queue:GetLen()
        return self.count
    end
    ---是否为空
    function Queue:IsEmpty()
        return self.count == 0
    end
    ---入队
    function Queue:Push(value)
        self.last = self.last + 1
        self[self.last] = value
        self.count = self.count + 1
    end
    ---出队
    function Queue:Pop()
        if self.count == 0 then print('Queue is empty.') return nil end
        local value = self[self.first]
        self[self.first] = nil
        self.first = self.first + 1
        self.count = self.count - 1
        return value
    end
    ---读取队首元素
    function Queue:Peek()
        if self.count == 0 then print('Queue is empty.') return nil end
        return self[self.first]
    end
    ---获取遍历队列内部元素的迭代器
    function Queue:GetIterator()
        local index = self.first - 1
        return function()
            index = index + 1
            return self[index]
        end
    end
    ---清空队列
    function Queue:Clear()
        if self.count == 0 then return end
        for i = self.first , self.last do
            self[i] = nil
        end
        self.count = 0
        self.first = 1
        self.last = 0
    end
    return Queue
end
--*************************  Custom Containner (end)  *************************
--*************************  Custom Module (start)  *************************
---对象池
function LuaKits.CreateObjectPool(obj,maxCount)
    local ObjPool = {}
    local self = ObjPool
    ---创建（复制）新对象
    local function CreateObj(obj)
        local ret = {}
        for k,v in pairs(obj)do
            ret[k] = v
        end
        return ret
    end
    ---初始化
    local function Init()
        local Stack = LuaKits.NewStack()
        self.pool =Stack:New()
        self.maxCount = maxCount or 0
        self.noRecycleCount = 0
        if self.maxCount > 0 then
            for i = 1 , self.maxCount do
                self.pool:Push(CreateObj(obj))
            end
        end
    end
    ---分配对象池中的对象
    function self.Spawn(createAlthoughtPoolIsEmpty)
        local ret = nil
        if self.pool:GetLen() > 0 then
            ret = self.pool:Pop()
            if not ret then
                if createAlthoughtPoolIsEmpty then
                    ret = CreateObj(obj)
                end
            end
            self.noRecycleCount = self.noRecycleCount + 1
        else
            if createAlthoughtPoolIsEmpty then
                ret = CreateObj(obj)
                self.noRecycleCount = self.noRecycleCount + 1
            end
        end
        return ret
    end
    ---回收对象到对象池中（只有对象真的回收到对象池中 才返回true）
    function self.Recycle(targetObject)
        if not targetObject then return false end
        if self.maxCount > 0 and self.pool:GetLen() >= self.maxCount then
            targetObject = nil
            self.noRecycleCount = self.noRecycleCount - 1
            return false
        end
        self.pool:Push(targetObject)
        self.noRecycleCount = self.noRecycleCount - 1
        return true
    end

    Init()
    return ObjPool
end
--*************************  Custom Module (end)  *************************
--*************************  UI (start)  ************************
---初始化 UI 组件，消除 Find 组件的操作，有性能消耗（函数堆栈 + 字符串分割）
---需要命名规范，不同组件有不同的命名前缀，且同一 UI 的各组件名字唯一
function LuaKits.InitUIComps(comps,gameobject)
    if not gameobject or gameobject.transform.childCount == 0 then return end
    local name = ''
    local prefix = ''
    for i = 0 , gameobject.transform.childCount - 1 do
        name = gameObject.transform:GetChild(i).gameObject.name
        prefix = LuaKits.Split(name,'_')[1]
        if prefix == '' then
            comps[name] = gameObject.transform:GetChild(i):GetComponent('')  --
        elseif prefix == '' then
            comps[name] = gameObject.transform:GetChild(i):GetComponent('')  --
        elseif prefix == '' then
            comps[name] = gameObject.transform:GetChild(i):GetComponent('')  --
        elseif prefix == '' then
            comps[name] = gameObject.transform:GetChild(i):GetComponent('')  --
        elseif prefix == '' then
            comps[name] = gameObject.transform:GetChild(i):GetComponent('')  --
        elseif prefix == '' then
            comps[name] = gameObject.transform:GetChild(i):GetComponent('')  --
        end
        LuaKits.InitUIComps(comps,gameObject.transform:GetChild(i).gameObject)
    end
end
--*************************  UI (end)  *************************
--*************************  Helper Function (start)  *************************
---字符串分割
function LuaKits.Split(fullStr,separator)
    local ret = {}
    local retKey = 1
    local findStartIndex = 1
    while true do
        local separatorIndex = string.find(fullStr,separator,findStartIndex)
        if not separatorIndex then
            ret[retKey] = string.sub(fullStr,findStartIndex,string.len(fullStr))
            break
        end
        ret[retKey] = string.sub(fullStr,findStartIndex,separatorIndex-1)
        findStartIndex = separatorIndex + string.len(separator)
        retKey = retKey + 1
    end
    return ret
end
--*************************  Helper Function (end)  *************************